package com.wits.media;

public class YuvBlit {

	public static class Plane {
		
		public byte[] data;
		public int offset;
		public int width;
		public int height;
		public int stride;
		
		public Plane() {
		}
		
		public Plane(byte[] data, int offset, int width, int height, int stride) {
			this.data = data;
			this.offset = offset;
			this.width = width;
			this.height = height;
			this.stride = stride;
		}
		
		public int size() {
			return width * height;
		}
	}
	
	public static class YuvPlanes {
		public Plane yPlane;
		public Plane uPlane;
		public Plane vPlane;
		
		public int width() {
			return yPlane.width;
		}
		
		public int height() {
			return yPlane.height;
		}
		
		public static YuvPlanes clipYV12(Plane plane, int x, int y, int width, int height) {
			final int frameSize = plane.width * plane.height;
			
			YuvPlanes planes = new YuvPlanes();
			
			int offset = y * plane.stride + x;
			planes.yPlane = new Plane(plane.data, plane.offset + offset, width, height, plane.stride);
			
			offset = frameSize + y * plane.stride/4 + x / 2;
			planes.uPlane = new Plane(plane.data, plane.offset + offset, width/2, height/2, plane.stride/2);
			
			offset = frameSize + frameSize/4 + y * plane.stride/4 + x / 2;
			planes.vPlane = new Plane(plane.data, plane.offset + offset, width/2, height/2, plane.stride/2);
			
			return planes;
		}
		
	}
	
	public static void copy(Plane src, Plane dest) {
		int width = src.width > dest.width ? dest.width : src.width;
		int height = src.height > dest.height ? dest.height : src.height;
		if (width <= 0 || height <= 0) {
			return;
		}
		
		for (int j = 0; j < height; j ++) {
			System.arraycopy(src.data, src.offset + j * src.stride, dest.data, dest.offset + j * dest.stride, width);
		}
	}

	public static void blitYV12(YuvPlanes src, YuvPlanes dest) {
		copy(src.yPlane, dest.yPlane);
		copy(src.uPlane, dest.uPlane);
		copy(src.vPlane, dest.vPlane);
	}

	public static void blitYV12Alpha(YuvPlanes src, YuvPlanes dest, int alpha) {
		int width = src.width() > dest.width() ? dest.width() : src.width();
		int height = src.height() > dest.height() ? dest.height() : src.height();
		if (width <= 0 || height <= 0) {
			return;
		}


		for (int row = 0; row < height; ++ row) {
			int srcYLine = src.yPlane.offset + src.yPlane.stride * row;
			int srcULine = src.uPlane.offset + src.uPlane.stride * (row / 2);
			int srcVLine = src.vPlane.offset + src.vPlane.stride * (row / 2);

			int dstYLine = dest.yPlane.offset + dest.yPlane.stride * row;
			int dstULine = dest.uPlane.offset + dest.uPlane.stride * (row/2);
			int dstVLine = dest.vPlane.offset + dest.vPlane.stride * (row/2);

			for (int i = 0; i < width; ++ i)
			{
				dest.yPlane.data[dstYLine] = (byte)(((src.yPlane.data[srcYLine] & 0xFF) * alpha + (dest.yPlane.data[dstYLine]& 0xFF) * (255 - alpha))/255);
				dest.uPlane.data[dstULine] = (byte)(((src.uPlane.data[srcULine] & 0xFF) * alpha + (dest.uPlane.data[dstULine]& 0xFF) * (255 - alpha))/255);
				dest.vPlane.data[dstVLine] = (byte)(((src.vPlane.data[srcVLine] & 0xFF) * alpha + (dest.vPlane.data[dstVLine]& 0xFF) * (255 - alpha))/255);

				dstYLine += 1;
				srcYLine += 1;

				if ((i % 2) == 1)
				{
					dstULine += 1;
					dstVLine += 1;

					srcULine += 1;
					srcVLine += 1;
				}
			}
		}
	}
	
	public static void blitYV12(YuvPlanes src, YuvPlanes dest, int color) {
		int width = src.width() > dest.width() ? dest.width() : src.width();
		int height = src.height() > dest.height() ? dest.height() : src.height();
		if (width <= 0 || height <= 0) {
			return;
		}
	    
	    Yuv yuv = new Yuv(color);
	    System.out.println("key color. " + yuv.y + "," + yuv.u + "," + yuv.v);
	    byte keyY = (byte)yuv.y;
	    byte keyU = (byte)yuv.u;
	    byte keyV = (byte)yuv.v;
	    
	    for (int row = 0; row < height; ++ row) {
	        int srcYLine = src.yPlane.offset + src.yPlane.stride * row;
	        int srcULine = src.uPlane.offset + src.uPlane.stride * (row / 2);
	        int srcVLine = src.vPlane.offset + src.vPlane.stride * (row / 2);

	        int dstYLine = dest.yPlane.offset + dest.yPlane.stride * row;
	        int dstULine = dest.uPlane.offset + dest.uPlane.stride * (row/2);
	        int dstVLine = dest.vPlane.offset + dest.vPlane.stride * (row/2);

	        for (int i = 0; i < width; ++ i)
	        {
	        	int y = src.yPlane.data[srcYLine] & 0xFF;
	        	int u = src.uPlane.data[srcULine] & 0xFF;
	        	int v = src.vPlane.data[srcVLine] & 0xFF;
//	        	if (y != yuv.y || u != yuv.u || v != yuv.v) {
	        	if ((src.yPlane.data[srcYLine] != keyY) ||
	        			(src.uPlane.data[srcULine] != keyU) ||
	        			(src.vPlane.data[srcVLine] != keyV)) {
	        		
	                //dstYLine[0] = srcYLine[0];
	                //dstULine[0] = srcULine[0];
	                //dstVLine[0] = srcVLine[0];

	        		dest.yPlane.data[dstYLine] = src.yPlane.data[srcYLine];
	        		dest.uPlane.data[dstULine] = src.uPlane.data[srcULine];
	        		dest.vPlane.data[dstVLine] = src.vPlane.data[srcVLine];
	            }

	            dstYLine += 1;
	            srcYLine += 1;

	            if ((i % 2) == 1)
	            {
	                dstULine += 1;
	                dstVLine += 1;
	            
	                srcULine += 1;
	                srcVLine += 1;
	            }
	        }
	    }
	}
	
	public static void blitYV12(YuvPlanes src, YuvPlanes dest, int color, int alpha) {
		int width = src.width() > dest.width() ? dest.width() : src.width();
		int height = src.height() > dest.height() ? dest.height() : src.height();
		if (width <= 0 || height <= 0) {
			return;
		}
	    
	    Yuv yuv = new Yuv(color);
	    byte keyY = (byte)yuv.y;
	    byte keyU = (byte)yuv.u;
	    byte keyV = (byte)yuv.v;
	    
	    for (int row = 0; row < height; ++ row) {
	        int srcYLine = src.yPlane.offset + src.yPlane.stride * row;
	        int srcULine = src.uPlane.offset + src.uPlane.stride * (row / 2);
	        int srcVLine = src.vPlane.offset + src.vPlane.stride * (row / 2);

	        int dstYLine = dest.yPlane.offset + dest.yPlane.stride * row;
	        int dstULine = dest.uPlane.offset + dest.uPlane.stride * (row/2);
	        int dstVLine = dest.vPlane.offset + dest.vPlane.stride * (row/2);

	        for (int i = 0; i < width; ++ i)
	        {
	        	if ((src.yPlane.data[srcYLine] != keyY) ||
	        			(src.uPlane.data[srcULine] != keyU) ||
	        			(src.vPlane.data[srcVLine] != keyV)) {
	        		
	                //dstYLine[0] = srcYLine[0];
	                //dstULine[0] = srcULine[0];
	                //dstVLine[0] = srcVLine[0];

	        		dest.yPlane.data[dstYLine] = (byte)(((src.yPlane.data[srcYLine] & 0xFF) * alpha + (dest.yPlane.data[dstYLine]& 0xFF) * (255 - alpha))/255);
	        		dest.uPlane.data[dstULine] = (byte)(((src.uPlane.data[srcULine] & 0xFF) * alpha + (dest.uPlane.data[dstULine]& 0xFF) * (255 - alpha))/255);
	        		dest.vPlane.data[dstVLine] = (byte)(((src.vPlane.data[srcVLine] & 0xFF) * alpha + (dest.vPlane.data[dstVLine]& 0xFF) * (255 - alpha))/255);
	            }

	            dstYLine += 1;
	            srcYLine += 1;

	            if ((i % 2) == 1)
	            {
	                dstULine += 1;
	                dstVLine += 1;
	            
	                srcULine += 1;
	                srcVLine += 1;
	            }
	        }
	    }
	}

	/**
	 * 根据掩码位图绘制
	 * @param mask 掩码位图
	 * @param dest
	 * @param keyColor	背景色
	 * @param alpha		透明度
	 * @param maskColor	前景色
	 */
	public static void blitYV12(YuvPlanes mask, YuvPlanes dest, int keyColor, int alpha, int maskColor) {
		int width = mask.width() > dest.width() ? dest.width() : mask.width();
		int height = mask.height() > dest.height() ? dest.height() : mask.height();
		if (width <= 0 || height <= 0) {
			return;
		}

		Yuv keyYuv = new Yuv(keyColor);
		byte keyY = (byte)keyYuv.y;
		byte keyU = (byte)keyYuv.u;
		byte keyV = (byte)keyYuv.v;

		Yuv maskYuv = new Yuv(maskColor);
		byte maskY = (byte)maskYuv.y;
		byte maskU = (byte)maskYuv.u;
		byte maskV = (byte)maskYuv.v;

		for (int row = 0; row < height; ++ row) {
			int srcYLine = mask.yPlane.offset + mask.yPlane.stride * row;
			int srcULine = mask.uPlane.offset + mask.uPlane.stride * (row / 2);
			int srcVLine = mask.vPlane.offset + mask.vPlane.stride * (row / 2);

			int dstYLine = dest.yPlane.offset + dest.yPlane.stride * row;
			int dstULine = dest.uPlane.offset + dest.uPlane.stride * (row/2);
			int dstVLine = dest.vPlane.offset + dest.vPlane.stride * (row/2);

			for (int i = 0; i < width; ++ i)
			{
				if ((mask.yPlane.data[srcYLine] != keyY) ||
						(mask.uPlane.data[srcULine] != keyU) ||
						(mask.vPlane.data[srcVLine] != keyV)) {

					dest.yPlane.data[dstYLine] = (byte)((maskY * alpha + (dest.yPlane.data[dstYLine]& 0xFF) * (255 - alpha))/255);
					dest.uPlane.data[dstULine] = (byte)((maskU * alpha + (dest.uPlane.data[dstULine]& 0xFF) * (255 - alpha))/255);
					dest.vPlane.data[dstVLine] = (byte)((maskV * alpha + (dest.vPlane.data[dstVLine]& 0xFF) * (255 - alpha))/255);
				}

				dstYLine += 1;
				srcYLine += 1;

				if ((i % 2) == 1)
				{
					dstULine += 1;
					dstVLine += 1;

					srcULine += 1;
					srcVLine += 1;
				}
			}
		}
	}
}
